﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EzyThirdLogic.ExtensionMethods;
using System.Collections;

namespace EzyThirdLogic
{
    public static class SuperfluousRemover
    {
        public static LinkedList<FunctionalDependencySet> ToFDSetList(FunctionalDependencySetCollection bigSet)
        {
            LinkedList<FunctionalDependencySet> listFDSet = new LinkedList<FunctionalDependencySet>();
            foreach (FunctionalDependencySet fdSet in bigSet.FDSetCollection)
            {
                listFDSet.AddLast(fdSet);
            }
            return listFDSet;
        }

        public static LinkedList<FunctionalDependencySet> SuperFluousCheck(LinkedList<FunctionalDependencySet> FDSetList)
        {
            bool restorable = false;
            bool nonessential = false;
            LinkedList<FunctionalDependencySet> listFDSet2 = FDSetList.Clone(); //clone
            LinkedList<FunctionalDependencySet> listFDSet3 = FDSetList.Clone();

            foreach (FunctionalDependencySet fdSet in listFDSet2)
            {
                BitArray primeAttr = GetPrimeAttr(fdSet);
                for (int i = primeAttr.NextSetBit(0); i >= 0; i = primeAttr.NextSetBit(i + 1))
                {
                    BitArray marked = new BitArray(26);
                    marked.Set(i, true);
                    FunctionalDependencySet gSet = CreateGSet(FDSetList, fdSet, marked);
                    LinkedList<BitArray> keysMarked = GetKeysMarked(GetKeys(fdSet), marked);
                    LinkedList<BitArray> keysWithoutMarked = GetKeysWithoutMarked(GetKeys(fdSet), marked);
                    if (keysWithoutMarked.Count != 0)
                    {
                        //check for restorability 
                        foreach (BitArray tempKey in keysWithoutMarked)
                        {
                            BitArray attrClosure = SynthesizingAlgorithm.AttributeClosure(gSet, tempKey);
                            attrClosure.And(marked);
                            //retorable
                            if (attrClosure.IsEquals(marked))
                            {
                                restorable = true;
                                break;
                            }
                        }
                        if (restorable)
                        {
                            foreach (BitArray tempKey1 in keysMarked)
                            {
                                BitArray attrClosure = SynthesizingAlgorithm.AttributeClosure(gSet, tempKey1);
                                foreach (BitArray tempkey2 in keysWithoutMarked)
                                {
                                    BitArray tempAtrrClosure = (BitArray)attrClosure.Clone();
                                    tempAtrrClosure.And(tempkey2);
                                    //non essential
                                    if (tempAtrrClosure.IsEquals(tempkey2))
                                    {
                                        nonessential = true;
                                        break;
                                    }
                                }
                                if (nonessential)
                                    break;
                            }
                        }
                    }
                    if (restorable && nonessential)
                    {
                        listFDSet3.Remove(fdSet);
                        FunctionalDependencySet fdSetTemp = new FunctionalDependencySet(fdSet);
                        LinkedList<BitArray> keysWithoutMarked2 = GetKeysWithoutMarked(GetKeys(fdSet), marked);
                        BitArray tempBit = new BitArray(26);
                        tempBit.Or(keysWithoutMarked2.ElementAt<BitArray>(0));
                        foreach (FunctionalDependency fd in fdSetTemp.FDSet)
                        {
                            FunctionalDependency tempFD = new FunctionalDependency(fd.LeftToStringWithDelimiter(), fd.RightToStringWithDelimiter());
                            FunctionalDependency tempFD2 = new FunctionalDependency(fd.LeftToStringWithDelimiter(), fd.RightToStringWithDelimiter());
                            BitArray tempMarked = new BitArray(26);
                            tempMarked.Or(marked);

                            tempFD.BitDeterminant.And(tempMarked);
                            if (tempFD.BitDeterminant.IsEquals(tempMarked))
                            {
                                tempFD2.BitDeterminant.SetAll(false);
                                tempFD2.BitDeterminant.Or(tempBit);
                            }
                            tempFD.BitDependent.And(tempMarked);
                            if (tempFD.BitDependent.IsEquals(tempMarked))
                            {
                                tempFD2.BitDependent.SetAll(false);
                                tempFD2.BitDependent.Or(tempBit);
                            }

                            FunctionalDependency newFD = new FunctionalDependency(FunctionalDependency.ToStringWithDelimiter(tempFD2.BitDeterminant), FunctionalDependency.ToStringWithDelimiter(tempFD2.BitDependent));
                            fdSet.RemoveFunctionalDependency(fd);
                            fdSet.AddFunctionalDependency(newFD);
                        }
                        listFDSet3.AddLast(fdSet);
                        break;
                    }
                }
                if (restorable && nonessential)
                {
                    SuperFluousCheck(listFDSet3);
                    break;
                }
            }
            return listFDSet3;
        }

        public static FunctionalDependencySet CreateGSet(LinkedList<FunctionalDependencySet> listFDSet, FunctionalDependencySet fdSet, BitArray marked)
        {
            FunctionalDependencySet newFDSet = new FunctionalDependencySet();
            LinkedList<FunctionalDependencySet> tmpList = listFDSet.Clone(); //clone
            tmpList.Remove(fdSet);
            foreach (FunctionalDependencySet fds in tmpList)
            {
                foreach (FunctionalDependency fd in fds.FDSet)
                {
                    newFDSet.AddFunctionalDependency(fd);
                }
            }
            LinkedList<BitArray> keys = GetKeysWithoutMarked(GetKeys(fdSet), marked);
            BitArray nonPrimeAttr = GetNonPrimeAttr(fdSet, marked);
            foreach (BitArray bitArray in keys)
            {
                FunctionalDependency tempFD = new FunctionalDependency(FunctionalDependency.ToStringWithDelimiter(bitArray), FunctionalDependency.ToStringWithDelimiter(nonPrimeAttr));
                newFDSet.AddFunctionalDependency(tempFD);
            }
            return newFDSet;
        }

        public static BitArray GetPrimeAttr(FunctionalDependencySet fdSet)
        {
            BitArray primeAttr = FunctionalDependency.ToBitArray('A');
            primeAttr.SetAll(false);
            foreach (FunctionalDependency fd in fdSet.FDSet)
            {
                BitArray temp = fd.BitDeterminant;
                primeAttr.Or(temp);
            }
            return primeAttr;
        }

        public static LinkedList<BitArray> GetKeys(FunctionalDependencySet fdSet)
        {
            LinkedList<BitArray> bitArray = new LinkedList<BitArray>();
            foreach (FunctionalDependency fd in fdSet.FDSet)
            {
                BitArray temp = (BitArray)fd.BitDeterminant.Clone();
                if (temp.Cardinality() > 1)
                    bitArray.AddLast(temp);
            }
            return bitArray;
        }

        public static LinkedList<BitArray> GetKeysWithoutMarked(LinkedList<BitArray> bitArray, BitArray marked)
        {
            LinkedList<BitArray> tempBitArray = bitArray.Clone(); //clone
            BitArray temp2 = new BitArray(26);
            foreach (BitArray array in bitArray)
            {
                temp2 = (BitArray)array.Clone();
                temp2.And(marked);
                if (temp2.IsEquals(marked))
                    tempBitArray.Remove(array);
            }
            return tempBitArray;
        }

        public static LinkedList<BitArray> GetKeysMarked(LinkedList<BitArray> bitArray, BitArray marked)
        {
            LinkedList<BitArray> tempBitArray = bitArray.Clone(); //clone
            BitArray temp2 = new BitArray(26);
            foreach (BitArray array in bitArray)
            {
                temp2 = (BitArray)array.Clone();
                temp2.And(marked);
                if (!temp2.IsEquals(marked))
                    tempBitArray.Remove(array);
            }
            return tempBitArray;
        }

        public static BitArray GetNonPrimeAttr(FunctionalDependencySet fdSet, BitArray marked)
        {
            BitArray leftAttr = FunctionalDependency.ToBitArray('A');
            leftAttr.SetAll(false);
            BitArray rightAttr = FunctionalDependency.ToBitArray('A');
            rightAttr.SetAll(false);
            foreach (FunctionalDependency fd in fdSet.FDSet)
            {
                BitArray tempLeft = fd.BitDeterminant;
                BitArray tempRight = fd.BitDependent;
                leftAttr.Or(tempLeft);
                rightAttr.Or(tempRight);
            }
            leftAttr.Or(rightAttr);
            leftAttr.Xor(marked);
            return leftAttr;
        }

        public static FunctionalDependencySetCollection RemoveSuperfluous(FunctionalDependencySetCollection bigSet)
        {
            FunctionalDependencySetCollection bigSet2 = new FunctionalDependencySetCollection();
            LinkedList<FunctionalDependencySet> listFDSet = ToFDSetList(bigSet);
            LinkedList<FunctionalDependencySet> listFDSet2 = SuperFluousCheck(listFDSet);
            foreach (FunctionalDependencySet fdSetq in listFDSet2)
            {
                bigSet2.AddFunctionalDependencySet(fdSetq);
            }
            return bigSet2;
        }

        public static String Superfluous_tostring(LinkedList<String> ll)
        {
            String res = "";
            for (int i = 0; i < ll.Count; i++)
            {
                res += ll.ElementAt<String>(i);
                res += "\n";
            }
            res += "\n";
            return res;
        }
    }
}
